#ifndef _AGM_FCB_H
#define _AGM_FCB_H

#include "util.h"
#include "dmac.h"

#define FCB FCB0 // This is the only FCB supported

// To store the config address of FPGA bit stream and it's complement value
#define FPGA_CONFIG_ADDR   0x81000030
#define FPGA_CONFIG_ADDR_N 0x81000034

#define FCB_CTRL_INIT       (1 << 0)
#define FCB_CTRL_WRITE      (1 << 1)
#define FCB_CTRL_READ       (1 << 2)
#define FCB_CTRL_UPDATE     (1 << 3)
#define FCB_CTRL_ACTIVATE   (1 << 4)
#define FCB_CTRL_DEACTIVATE (1 << 5)
#define FCB_CTRL_AUTO       (1 << 6)
#define FCB_CTRL_DMA        (1 << 7)

#define FCB_STAT_INIT       (1 << 0)
#define FCB_STAT_ACTIVE     (1 << 1)
#define FCB_STAT_ERR_ID     (1 << 4)
#define FCB_STAT_ERR_HEADER (1 << 5)
#define FCB_STAT_ERR_CRC    (1 << 6)
#define FCB_STAT_ERR_ALL (FCB_STAT_ERR_ID | FCB_STAT_ERR_HEADER | FCB_STAT_ERR_CRC)

#define FCB_AUTO_WORDS     (99944 / 4)

typedef struct
{
  __IO uint32_t CTRL; // 0x00
  __IO uint32_t ADDR; // 0x04
  __IO uint32_t DATA; // 0x08
  __IO uint32_t AUTO; // 0x0c
  __IO uint32_t STAT; // 0x10
  __IO uint32_t INT;  // 0x14
} FCB_TypeDef;

// The non-error bits in STAT register are read only. The error bits are cleared by writing 1.
static inline bool FCB_IsInit(void)        { return FCB->STAT & FCB_STAT_INIT;       }
static inline bool FCB_IsActive(void)      { return FCB->STAT & FCB_STAT_ACTIVE;     }
static inline bool FCB_IsErrorID(void)     { return FCB->STAT & FCB_STAT_ERR_ID;     }
static inline bool FCB_IsErrorHeader(void) { return FCB->STAT & FCB_STAT_ERR_HEADER; }
static inline bool FCB_IsErrorCrc(void)    { return FCB->STAT & FCB_STAT_ERR_CRC;    }
static inline bool FCB_IsAnyError(void)    { return FCB->STAT & FCB_STAT_ERR_ALL;    }
static inline void FCB_ClearErrors(void)   { FCB->STAT = FCB_STAT_ERR_ALL; }

static inline void FCB_EnableInt(uint32_t bits)  { FCB->INT |=  bits; }
static inline void FCB_DisableInt(uint32_t bits) { FCB->INT &= ~bits; }
static inline void FCB_ClearInt(void)            { FCB->INT = 0; FCB_ClearErrors(); }

static inline void FCB_Activate(void)   { FCB->CTRL |= FCB_CTRL_ACTIVATE;   }
static inline void FCB_DeActivate(void) { FCB->CTRL |= FCB_CTRL_DEACTIVATE; }

ReturnCodeTypedef FCB_AutoConfig(uint32_t config_addr);
ReturnCodeTypedef FCB_AutoConfigDma(uint32_t config_addr, DMAC_ChannelNumTypeDef channel);
ReturnCodeTypedef FCB_AutoDecompress(uint32_t config_addr);

#endif
